package top.goldenyear.porpoise.infra.storage.core.util;

import java.time.Duration;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import top.goldenyear.porpoise.common.core.exception.ErrorCode;
import top.goldenyear.porpoise.common.core.exception.ServiceException;
import top.goldenyear.porpoise.common.core.model.Ret;
import top.goldenyear.porpoise.infra.storage.config.FileConfig;
import top.goldenyear.porpoise.infra.storage.core.enums.StorageType;
import top.goldenyear.porpoise.infra.storage.core.model.Media;
import top.goldenyear.porpoise.infra.storage.core.service.FileClient;
import top.goldenyear.porpoise.infra.storage.core.service.db.DbFileClient;
import top.goldenyear.porpoise.infra.storage.core.service.exception.PorpoiseFileException;
import top.goldenyear.porpoise.infra.storage.core.service.local.LocalFileClient;
import top.goldenyear.porpoise.infra.storage.core.service.s3.S3FileClient;

/**
 * @author airhead
 */
public class FileClientUtils {
  private static final Map<String, FileClient> FILE_CLIENT_MAP = new ConcurrentHashMap<>();
  private static FileClient mainClient = null;

  public static void setDefault(String configId) {
    FileClient fileClient = FILE_CLIENT_MAP.get(configId);
    if (fileClient == null) {
      throw new ServiceException(ErrorCode.builder().msg("文件配置不存在，先添加配置").build());
    }

    mainClient = fileClient;
  }

  public static void add(String configId, FileConfig fileConfig) {
    add(configId, fileConfig, false);
  }

  public static void add(String configId, FileConfig fileConfig, boolean isDefault) {
    StorageType storageType = StorageType.of(fileConfig.getStorageType());
    FileClient fileClient =
        switch (storageType) {
          case Local -> new LocalFileClient(configId, fileConfig);
          case S3 -> new S3FileClient(configId, fileConfig);
          case Db -> new DbFileClient(configId, fileConfig);
        };

    FILE_CLIENT_MAP.put(configId, fileClient);
    // 更新 defaultFileClient
    if (isDefault) {
      mainClient = fileClient;
    } else {
      if (mainClient == null) {
        mainClient = fileClient;
      }
    }
  }

  public static FileClient use(String configId) {
    return FILE_CLIENT_MAP.get(configId);
  }

  /**
   * 是否存在
   *
   * @param bucket 存储桶
   * @param key 存储键
   */
  public static boolean exists(String bucket, String key) throws PorpoiseFileException {
    validateClient();

    return mainClient.exists(bucket, key);
  }

  /**
   * 是否存在
   *
   * @param key 存储键
   */
  public static boolean exists(String key) throws PorpoiseFileException {
    validateClient();

    return mainClient.exists(key);
  }

  /**
   * 获取文件临时地址
   *
   * @param bucket 存储桶
   * @param key 存储键
   */
  public static String getTempUrl(String bucket, String key, Duration duration)
      throws PorpoiseFileException, UnsupportedOperationException {
    validateClient();

    return mainClient.getTempUrl(bucket, key, duration);
  }

  /**
   * 获取文件临时地址
   *
   * @param key 存储键
   */
  public static String getTempUrl(String key, Duration duration)
      throws PorpoiseFileException, UnsupportedOperationException {
    validateClient();

    return mainClient.getTempUrl(key, duration);
  }

  /**
   * 获取文件临时地址
   *
   * @param bucket 存储桶
   * @param key 存储键
   */
  public static String getTempUrl(String bucket, String key, Date expiration)
      throws PorpoiseFileException, UnsupportedOperationException {
    validateClient();

    return mainClient.getTempUrl(bucket, key, expiration);
  }

  /**
   * 获取文件临时地址
   *
   * @param key 存储键
   */
  public static String getTempUrl(String key, Date expiration)
      throws PorpoiseFileException, UnsupportedOperationException {
    validateClient();

    return mainClient.getTempUrl(key, expiration);
  }

  /**
   * 获取文件
   *
   * @param bucket 存储桶
   * @param key 存储键
   */
  public static Media get(String bucket, String key) throws PorpoiseFileException {
    validateClient();

    return mainClient.get(bucket, key);
  }

  /**
   * 获取文件
   *
   * @param key 存储键
   */
  public static Media get(String key) throws PorpoiseFileException {
    validateClient();

    return mainClient.get(key);
  }

  /**
   * 推入文件
   *
   * @param bucket 存储桶
   * @param key 存储键
   * @param media 媒体
   */
  public static Ret put(String bucket, String key, Media media) throws PorpoiseFileException {
    validateClient();

    return mainClient.put(bucket, key, media);
  }

  /**
   * 推入文件
   *
   * @param key 存储键
   * @param media 媒体
   */
  public static Ret put(String key, Media media) throws PorpoiseFileException {
    validateClient();

    return mainClient.put(key, media);
  }

  /**
   * 删除文件
   *
   * @param bucket 存储桶
   * @param key 存储键
   */
  public static Ret delete(String bucket, String key) throws PorpoiseFileException {
    validateClient();

    return mainClient.delete(bucket, key);
  }

  /**
   * 删除文件
   *
   * @param key 存储键
   */
  public static Ret delete(String key) {
    validateClient();

    return mainClient.delete(key);
  }

  /**
   * 批量删除文件
   *
   * @param bucket 存储桶
   * @param keys 存储键集合
   */
  public static Ret deleteBatch(String bucket, Collection<String> keys)
      throws PorpoiseFileException {
    validateClient();

    return mainClient.deleteBatch(bucket, keys);
  }

  /**
   * 批量删除文件
   *
   * @param keys 存储键集合
   */
  public static Ret deleteBatch(Collection<String> keys) throws PorpoiseFileException {
    validateClient();

    return mainClient.deleteBatch(keys);
  }

  public static void validateClient() {
    if (mainClient == null) {
      throw new ServiceException(ErrorCode.builder().msg("默认文件配置不存在，先添加配置").build());
    }
  }
}
